package com.desire.test;

import java.util.concurrent.TimeUnit;

/**
 * @author LittleDesire
 * @description
 * @date 2022-02-09 周三 10:39
 * @since 17
 */
public class _49_notify_notifyAll {
    /**
     * 如果线程调用了对象的 wait()方法，那么线程便会处于该对象的等待池中，等待池中的线程不会去竞争该对象的锁。
     * <p>
     * 当有线程调用了对象的 notifyAll()方法（唤醒所有 wait 线程）或 notify()方法（只随机唤醒一个 wait 线程），
     * 被唤醒的线程进入该对象的锁池中，锁池中的线程会去竞争该对象锁。也就是说，
     * 调用了notify后只要一个线程会由等待池进入锁池，而notifyAll会将该对象等待池内的所有线程移动到锁池中，等待锁竞争
     * <p>
     * 优先级高的线程竞争到对象锁的概率大，假若某线程没有竞争到该对象锁，它还会留在锁池中，唯有线程再次调用 wait()方法，
     * 它才会重新回到等待池中。而竞争到对象锁的线程则继续往下执行，直到执行完了 synchronized 代码块，它会释放掉该对象锁，
     * 这时锁池中的线程会继续竞争该对象锁。
     * <p>
     * 所谓唤醒线程，另一种解释可以说是将线程由等待池移动到锁池，notifyAll调用后，会将全部线程由等待池移到锁池，
     * 然后参与锁的竞争，竞争成功则继续执行，如果不成功则留在锁池等待锁被释放后再次参与竞争。而notify只会唤醒一个线程。
     */


    public static void main(String[] args) throws InterruptedException {

        Object co = new Object();
        for (int i = 0; i < 5; i++) {
            MyThread t = new MyThread("Thread" + i, co);
            t.start();
        }


        // 主线程,
        TimeUnit.SECONDS.sleep(2);
        System.out.println("-----Main Thread notify-----");
        synchronized (co) {
            // 只唤醒了一个线程,,  一共开启了 5 个线程 外加一个main 线程 (唤醒谁,未知)
            //co.notify();

            // 唤醒所有线程
            co.notifyAll();
        }
        TimeUnit.SECONDS.sleep(2);
        System.out.println("Main Thread is end.");


    }

    static class MyThread extends Thread {
        private final String name;
        private final Object co;

        public MyThread(String name, Object o) {
            this.name = name;
            this.co = o;
        }

        @Override
        public void run() {
            System.out.println(name + " is waiting.");
            try {
                synchronized (co) {
                    co.wait();
                }
                System.out.println(name + " has been notified.");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
